﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
using System.Reflection;
using JoyfulHomeJourney.BackEnd.Repository.Interfaces;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using JoyfulHomeJourney.BackEnd.Infrastructure.Tools;

namespace JoyfulHomeJourney.BackEnd.Repository.Instances
{
    public class Repository<T> : IRepository<T> where T : class, new()
    {
        protected readonly DbContext _dbContext;
        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }

        public DbContext GetContext()
        {
            return _dbContext;
        }

        /// <summary>
        /// 在传入方法中执行的所有操作都会被视为一个事务,错误仍然会抛出但事务会回滚。
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task ExecuteInTransactionAsync(Func<Task> action)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync();
            try
            {
                await action();
                await transaction.CommitAsync();
            }
            catch (Exception)
            {
                await transaction.RollbackAsync();
                throw; // 重新抛出异常
            }
        }
        /// <summary>
        /// 在传入方法中执行的所有操作都会被视为一个事务,错误仍然会抛出但事务会回滚。如果外部变量在中受到了更改可以在fail中恢复，如果只是一次请求有效则不必，因为后续代码受报错影响不会执行。
        /// </summary>
        /// <param name="action"></param>
        /// <param name="fail"></param>
        /// <returns></returns>
        public async Task ExecuteInTransactionAsync(Func<Task> action,Func<Task> fail)
        {
            using var transaction = await _dbContext.Database.BeginTransactionAsync();
            try
            {
                await action();
                await transaction.CommitAsync();
            }
            catch (Exception)
            {
                await transaction.RollbackAsync();
                throw; // 重新抛出异常
            }
        }

        public int Add(T t)
        {
            // 使用反射找到主键
            var entityType = _dbContext.Model.FindEntityType(typeof(T));
            var key = entityType.FindPrimaryKey();
            var keyProperty = key.Properties.FirstOrDefault();

            if (keyProperty != null && keyProperty.ClrType == typeof(string))
            {
                // 生成新的字符串 ID
                var newId = Tools.Guid_2();
                // 使用 DbContext 设置属性值
                _dbContext.Entry(t).Property(keyProperty.Name).CurrentValue = newId;
            }
            TSet().Add(t);
            return Save();
        }
        public int Add(IEnumerable<T> ie)
        {
            foreach (var t in ie)
            {
                // 使用反射找到主键
                var entityType = _dbContext.Model.FindEntityType(typeof(T));
                var key = entityType.FindPrimaryKey();
                var keyProperty = key.Properties.FirstOrDefault();

                if (keyProperty != null && keyProperty.ClrType == typeof(string))
                {
                    // 生成新的字符串 ID
                    var newId = Tools.Guid_2();
                    // 使用 DbContext 设置属性值
                    _dbContext.Entry(t).Property(keyProperty.Name).CurrentValue = newId;
                }
            }
            TSet().AddRange(ie);
            return Save();
        }

        public async Task<int> AddAsync(T t)
        {
            // 使用反射找到主键
            var entityType = _dbContext.Model.FindEntityType(typeof(T));
            var key = entityType.FindPrimaryKey();
            var keyProperty = key.Properties.FirstOrDefault();
            if (keyProperty != null && keyProperty.ClrType == typeof(string))
            {
                // 生成新的字符串 ID
                var newId = Tools.Guid_1();
                // 使用 DbContext 设置属性值
                _dbContext.Entry(t).Property(keyProperty.Name).CurrentValue = newId;
            }
           await TSet().AddAsync(t);
            return await SaveAsync();
        }
        public async Task<int> AddAsync(T t,string id)
        {
            // 使用反射找到主键
            var entityType = _dbContext.Model.FindEntityType(typeof(T));
            var key = entityType.FindPrimaryKey();
            var keyProperty = key.Properties.FirstOrDefault();
            if (keyProperty != null && keyProperty.ClrType == typeof(string))
            {
                // 生成新的字符串 ID
                var newId = id;
                // 使用 DbContext 设置属性值
                _dbContext.Entry(t).Property(keyProperty.Name).CurrentValue = newId;
            }
           await TSet().AddAsync(t);
            return await SaveAsync();
        }

        public Task<int> AddAsync(IEnumerable<T> ie)
        {
            foreach (var t in ie)
            {
                // 使用反射找到主键
                var entityType = _dbContext.Model.FindEntityType(typeof(T));
                var key = entityType.FindPrimaryKey();
                var keyProperty = key.Properties.FirstOrDefault();

                if (keyProperty != null && keyProperty.ClrType == typeof(string))
                {
                    // 生成新的字符串 ID
                    var newId = Tools.Guid_2();
                    // 使用 DbContext 设置属性值
                    _dbContext.Entry(t).Property(keyProperty.Name).CurrentValue = newId;
                }
            }
            TSet().AddRange(ie);
            return SaveAsync();
        }

        public int Delete(T t)
        {
            TSet().Remove(t);
            return Save();
        }

        public int Delete(IEnumerable<T> ie)
        {
            TSet().RemoveRange(ie);
            return Save();
        }

        public Task<int> DeleteAsync(T t)
        {
            TSet().Remove(t);
            return SaveAsync();
        }

        public Task<int> DeleteAsync(IEnumerable<T> ie)
        {
            TSet().RemoveRange(ie);
            return SaveAsync();
        }

        public IQueryable<T> Pagination1<TKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TKey>> order, out int total, int page, int limit)
        {
            var iq = Query(where);
            total = iq.Count();
            if (isAsc)
            {
                iq = iq.OrderBy(order);
            }
            else
            {
                iq = iq.OrderByDescending(order);
            }
            return iq.Skip((page - 1) * limit).Take(limit);
        }
        /// <summary>
        /// 使用字段名进行排序
        /// </summary>
        /// <param name="where"></param>
        /// <param name="isAsc"></param>
        /// <param name="field"></param>
        /// <param name="total"></param>
        /// <param name="page"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public IQueryable<T> Pagination1(Expression<Func<T, bool>> where, bool isAsc, string field, out int total, int page, int limit)
        {
            var iq = Query(where);
            total = iq.Count();
            iq = ApplySorting(iq, field, isAsc);
            return iq.Skip((page - 1) * limit).Take(limit);
        }
        private IQueryable<Item> ApplySorting<Item>(IQueryable<Item> query, string sortBy, bool isAsc)
        {
            // 判断排序字段是否合法，避免SQL注入攻击
            var propertyInfo = typeof(Item).GetProperty(sortBy, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            if (propertyInfo == null)
            {
                return query;
            }

            // 动态构建排序表达式
            var parameter = Expression.Parameter(typeof(Item), "x");
            var property = Expression.Property(parameter, propertyInfo);
            var lambda = Expression.Lambda(property, parameter);

            // 根据排序顺序选择升序或降序
            var orderByMethod = isAsc ? "OrderBy" : "OrderByDescending";
            var methodCallExpression = Expression.Call(
                typeof(Queryable), orderByMethod,
                new Type[] { typeof(Item), propertyInfo.PropertyType },
                query.Expression, Expression.Quote(lambda)
            );

            return query.Provider.CreateQuery<Item>(methodCallExpression);
        }


        

        public IQueryable<T> Query()
        {
            return TSet();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where)
        {
            return TSet().Where(where);
        }

        public IQueryable<T> Query<TKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TKey>> order)
        {
            var iq = Query(where);
            if (isAsc)
            {
                iq = iq.OrderBy(order);
            }
            else
            {
                iq = iq.OrderByDescending(order);
            }
            return iq;
        }

        public async Task<int> SaveAsync()
        {
            try
            {
                return await _dbContext.SaveChangesAsync();

            }
            catch(Exception e)
            {
                throw e;
            }
        }

        public int Save()
        {
            return _dbContext.SaveChanges();
        }

        public DbSet<T> TSet()
        {
            return _dbContext.Set<T>();
        }



        private readonly List<string> ignoreUpdatePropertyName = new List<string>()
        {
            "CreateAt",
            "ParentId",
            "CreateTime"
        };
        private bool IsIgnore(string name)
        {
            bool flag = false;
            foreach (var iName in ignoreUpdatePropertyName)
            {
                if (name.ToLower().Contains(iName.ToLower()))
                {
                    flag = true;
                    break;
                }
            }
            return flag;
        }
        public int UpdateAllProper(T t)
        {
            TSet().Update(t);
            return Save();
        }

        public Task<int> UpdateAllProperAsync(T t)
        {
            TSet().Update(t);
            return SaveAsync();
        }

        public int UpdateAllProper(IEnumerable<T> ie)
        {
            TSet().UpdateRange(ie);
            return Save();
        }

        public Task<int> UpdateAllProperAsync(IEnumerable<T> ie)
        {
            TSet().UpdateRange(ie);
            return SaveAsync();
        }

        public int UpdateAllProperNotNull(T entity)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体对象的所有属性值
            object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            // 获取实体的主键值
            var keyValue = primaryKey.PropertyInfo.GetValue(entity);

            // 查询数据库中对应的实体
            var dbEntity = _dbContext.Set<T>().Find(keyValue);

            if (dbEntity != null)
            {
                // 更新非空属性
                foreach (var property in properties)
                {
                    if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                    {
                        property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                    }
                }
            }

            return Save(); // 假设更新成功
        }

        public async Task<int> UpdateAllProperNotNullAsync(T entity)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体对象的所有属性值
            object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            // 获取实体的主键值
            var keyValue = primaryKey.PropertyInfo.GetValue(entity);

            // 查询数据库中对应的实体
            var dbEntity = await _dbContext.Set<T>().FindAsync(keyValue);

            if (dbEntity != null)
            {
                // 更新非空属性
                foreach (var property in properties)
                {
                    if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                    {
                        property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                    }
                }
            }

            return await SaveAsync(); // 假设更新成功
        }

        public int UpdateAllProperNotNull(IEnumerable<T> entities)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            foreach (var entity in entities)
            {
                // 获取实体对象的所有属性值
                object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

                // 获取实体的主键值
                var keyValue = primaryKey.PropertyInfo.GetValue(entity);

                // 查询数据库中对应的实体
                var dbEntity = _dbContext.Set<T>().Find(keyValue);

                if (dbEntity != null)
                {
                    // 更新非空属性
                    foreach (var property in properties)
                    {
                        if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                        {
                            property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                        }
                    }
                }
            }

            // 保存更改
            return Save();
        }

        public async Task<int> UpdateAllProperNotNullAsync(IEnumerable<T> entities)
        {
            // 获取实体对象的类型
            Type entityType = typeof(T);

            // 获取实体对象的所有属性
            PropertyInfo[] properties = entityType.GetProperties();

            // 获取实体的主键属性
            var primaryKey = _dbContext.Model.FindEntityType(entityType).FindPrimaryKey().Properties[0];

            foreach (var entity in entities)
            {
                // 获取实体对象的所有属性值
                object[] values = properties.Select(p => p.GetValue(entity)).ToArray();

                // 获取实体的主键值
                var keyValue = primaryKey.PropertyInfo.GetValue(entity);

                // 查询数据库中对应的实体
                var dbEntity = await _dbContext.Set<T>().FindAsync(keyValue);

                if (dbEntity != null)
                {
                    // 更新非空属性
                    foreach (var property in properties)
                    {
                        if (property != primaryKey.PropertyInfo && property.GetGetMethod() != null && !property.GetGetMethod().IsVirtual && !IsIgnore(property.Name) && values[properties.ToList().IndexOf(property)] != null)
                        {
                            property.SetValue(dbEntity, values[properties.ToList().IndexOf(property)]);
                        }
                    }
                }
            }

            // 保存更改
            return await SaveAsync();
        }
        
    }
}
